﻿#include "study10.h"
// C/C++ 标准库学习网站：https://legacy.cplusplus.com
// C/C++ 微软(Visual Studio)中文学习网站：https://learn.microsoft.com/zh-cn/cpp/cpp/?view=msvc-170

/*
结构化绑定需要 C++17 以上的语法才有效，所以需要在编译器选项中开启 C++17 标准（还是注意平台与模式）：
    右键项目 -> 属性 -> C/C++ -> 语言 -> C++语言标准 -> ISO C++17 标准 (/std:c++17)
    结构化绑定语法：
        auto[var1, var2,...] = expression; // 结构化绑定，将表达式的值绑定到变量 var1、var2、... 上

在 C++17 中，有一个 std::optional 类型（头文件：<optional>），
    可以用来处理可能不存在的值，使用参见本项目 study02 示例; 此外还有多类型数据处理类，如下：
    std::variant 类型（头文件：<variant>）可以用来处理多种类型的值，使用参见本项目 study02 示例：
        variant 类是将所有可能得数据类型存储为单独的变量作为单独的成员（底层还是联合体）
    std::any 类型（头文件：<any>）可以用来处理任意类型的值，使用参见本项目 study02 示例：
        大致原理为：小型类型的数据是使用联合体储存，当超过某一个大小（大概是几十个字节）后变成大类型，
        大型类型的数据推测是使用堆内存存储（动态内存管理的）
    一个建议：实际在处理多类型数据时，少使用 std::any，因为其可能会有性能问题，
        可以使用 std::variant、std::optional 代替。

当需要处理多个操作时（比如读取多个文件）可以使用多个线程，或者使用 std::async 库，
    C++ 中的异步 std::async 与 std::future 库，在头文件：<future> 中，
    可以用来处理异步执行任务，使用参见本项目 study03 示例，根据微软官网 <future> 函数的描述，简单说明语法如下：
        template <class Fn, class... ArgTypes>
        future<typename result_of<Fn(ArgTypes...)>::type>
            async(Fn&& fn, ArgTypes&&... args);
    或者：
        template <class Fn, class... ArgTypes>
        future<typename result_of<Fn(ArgTypes...)>::type>
            async(launch policy, Fn&& fn, ArgTypes&&... args);
        第一个模板参数 Fn 是一个可调用对象（函数指针），第二个模板参数 ArgTypes 是一个参数包（函数指针的参数），
        第三个模板参数 result_of<Fn(ArgTypes...)>::type 是一个类型别名，它表示函数 Fn 的返回值类型。
        该函数返回一个 future 对象，该对象可以用来获取异步执行的结果。
        该函数的 launch 参数可以指定任务的执行策略，默认是异步（std::launch::async）。
        C++ 标准库的并行线程池默认是 500 个
    std::future 类的 wait() 函数可以用来等待异步执行的任务完成。
    我们在使用异步函数时，有时会和互斥锁 (mutex) 结合使用，以避免数据冲突。
        C++ 的互斥锁 (mutex) 库在头文件：<mutex> 中，可以使用 std::lock_guard 类来自动获取互斥锁，
        并在离开作用域时自动释放互斥锁；语法如下：
            std::mutex mutex; // 声明互斥锁，注意作用域
            std::lock_guard<std::mutex> lock(mutex); // 获取互斥锁
            { // 互斥锁保护的代码块 } // 互斥锁保护的代码块，大括号没有意义，不用写
            mutex.unlock(); // 释放互斥锁
    调试小技巧：查看调试时的并行堆栈：调试过程点击菜单栏中的“调试” -> “窗口” -> “并行堆栈”

字符串优化：
    在 C++17 中，可以使用 std::string_view 类来优化字符串的处理，头文件为 <string_view>，
    它是一个只读的字符串视图，可以避免拷贝字符串，提高性能；但是它只能处理常量字符串，不能修改字符串内容；
    标准库 std::string 中，对小字符串（长度小于等于 15 个字符，不含 '\0'）在 Release 模式下使用栈空间分配，
    而对大字符串（长度大于 15 个字符，含 '\0'）在堆空间分配；在 Debug 模式下，所有字符串都在堆空间分配（因为预处理的）；

单例模式的测试，参见 study05 示例；注意使用命名空间就不能将 static 变量赋值给其他变量。
*/
int main()
{
    // 复习返回值、返回结构体，以及结构化绑定测试
    print_start("结构化绑定测试部分");
    test_return_value();
    print_end("结构化绑定测试部分");

    // 处理可能不存在的数据测试
    print_start("处理可能不存在的数据测试部分");
    test_optional();
    print_end("处理可能不存在的数据测试部分");

    // 处理多种类型的值测试
    print_start("处理多种类型的值测试部分");
    test_more_types();
    print_end("处理多种类型的值测试部分");
    
    // 处理任意类型的值测试
    print_start("处理任意类型的值测试部分");
    test_any_type();
    print_end("处理任意类型的值测试部分");

    // 异步执行任务测试
    /*test_async_task();
    test_read_file();
    cout << "异步执行任务测试结束\n\n"; */

    // 字符串优化测试
    print_start("字符串优化测试部分");
    test_string_view();
    print_end("字符串优化测试部分");

    // 单例模式测试
    print_start("单例模式测试部分");
    test_singleton();
    print_end("单例模式测试部分");

    system("pause"); // 等待用户输入
    return 0;
}